# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         ext_method_debuger.py
# Description:  扩展方法执行器
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2020/12/10 15:38
# -------------------------------------------------------------------------------
import builtins
import json
import logging
import types

from apps.HttpAutoTestService.core import ext_methods
from apps.HttpAutoTestService.core.ext_methods import *
from apps.HttpAutoTestService.core.extractor import Extractor
from apps.HttpAutoTestService.core.utils import parse_ext_method_args
from apps.HttpAutoTestService.core.validator import Validator
from utils.common import CJsonEncoder

logger = logging.getLogger(__name__)


class ExtMethodDebuger(object):

    def __init__(self):
        # 扩展函数
        self.ext_methods = {}
        # 系统内置函数
        self.builtins = {}
        for name, item in vars(ext_methods).items():
            if isinstance(item, types.FunctionType):
                self.ext_methods[name] = item

        for name, item in vars(builtins).items():
            if isinstance(item, types.BuiltinFunctionType):
                self.builtins[name] = item

    def debug(self, http_session_context=None, name=None, ext_method=None, expect_result=None):
        """
        执行扩展方法
        Args:
            http_session_context:
            name: 需要执行的扩展方法名称
            ext_method: 需要执行的扩展方法
            expect_result: 期望结果

        Returns:

        """
        # 执行时间
        variables_mapping = {**http_session_context.session_variables_mapping,
                             **http_session_context.output_variables_mapping}
        ext_method = parse_ext_method_args(content=ext_method, variables_mapping=variables_mapping)
        logger.info('执行{}扩展方法'.format(ext_method))

        method_name = ext_method.split('(')[0]
        ext_method_result = {
            "name": name or method_name,
            "ext_method": ext_method
        }

        if method_name in self.ext_methods or method_name in self.builtins:
            # 期望结果
            expect_result = parse_ext_method_args(content=expect_result, variables_mapping=variables_mapping)
            expect_result = json.loads(expect_result) if expect_result else {}
            logger.info('期望结果：{expect_result}'.format(expect_result=expect_result))

            result = eval(ext_method)

            if result and isinstance(expect_result, dict) and expect_result.get('output'):
                # 创建提取器
                extractor = Extractor()
                # 统一格式化扩展方法的输出变量output
                extractor.uniform_output(expect_result.get("output"))
                # 提取输出变量
                output_mapping = extractor.extract_output(resp_obj={'results': result})
                # 将提取的输出变量值更新到http_session_context实例的update_output_variables变量中
                http_session_context.update_output_variables(variables_mapping=output_mapping)

            validate_pass = failure_reason = None
            if isinstance(expect_result, dict) and expect_result.get('validate', None):
                # 创建校验器
                validator = Validator()
                # 统一格式化扩展方法的校验变量validate
                validator.uniform_validate(expect_result.get("validate"))
                variables_mapping = {**http_session_context.session_variables_mapping,
                                     **http_session_context.output_variables_mapping}
                validate_variables_list = parse_ext_method_args(content=validator.validate_variables_list,
                                                                variables_mapping=variables_mapping)
                validator.validate_variables_list = json.loads(
                    validate_variables_list) if validate_variables_list else []
                validate_pass, failure_reason = validator.validate(resp_obj={'results': result})

            ext_method_result.update({
                "ext_method_run_result": json.dumps(result, cls=CJsonEncoder, ensure_ascii=False),
                "status": validate_pass,
                "failure_reason": json.dumps(failure_reason, ensure_ascii=False)
            })

            if validate_pass == 'FAIL':
                logger.warning('扩展方法：{method_name}，调试未通过；原因：{failure_reason}'.format(method_name=method_name,
                                                                                     failure_reason=failure_reason))
        return ext_method_result
